package com.king.platform.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Calendar;
import java.util.Map;

/**
 * @author 1065246
 * @description:
 * @createTime:2023/3/2 13:35
 */
@Slf4j
public class JWTUtil {
  /**
   * 签名秘钥 此签名为 pwd的sha256大写
   * SecureUtil.sha256("pwd").toUpperCase()
   */
  private static final String SIGN_KEY = "7D5703BFD49B6CFE16F79A8A8F539DC5E2C3A8E203F00C09538E47AE26F8B03D";

  /**
   * 默认的过期时间:分钟
   */
  private static final Integer DEFAULT_EXPIRES = 60 * 60;

  /**
   * token默认的长度
   */
  private static final Integer DEFAULT_TOKEN_SIZE = 3;

  /**
   * 生成令牌
   *
   * @param payload     数据正文
   * @param expires 过期时间，单位(秒)
   */
  public static String getToken(Map<String, String> payload, Integer expires) throws Exception {
    //创建日历
    Calendar instance = Calendar.getInstance();
    //设置过期时间
    instance.add(Calendar.SECOND, expires);

    //创建jwt builder对象
    JWTCreator.Builder builder = JWT.create();

    //payload
    payload.forEach((k, v) -> {
      builder.withClaim(k, v);
    });

    //指定过期时间
    String token = builder.withExpiresAt(instance.getTime())//设置加密方式
        .sign(Algorithm.HMAC256(SIGN_KEY));
    //返回tokean
    return confoundPayload(token);
  }

  public static DecodedJWT verify(String token) throws Exception {
    try {
      //解析token
      String dToken = deConfoundPayload(token);
      //创建返回结果
      return JWT.require(Algorithm.HMAC256(SIGN_KEY)).build().verify(dToken);
    } catch (Exception ex) {
      throw new RuntimeException("token解析失败！！");
    }
  }


  /**
   * 对一个base64编码进行混淆  此处还可以进行replace混淆，考虑到效率问题，这里就不做啦~
   * 对于加密的思路还有位移、字符替换等~
   *
   * @param token 混淆payload前的token
   */
  private static String confoundPayload(String token) throws Exception {
    //分割token
    String[] split = token.split("\\.");
    //如果token不符合规范
    if (split.length != DEFAULT_TOKEN_SIZE) {
      throw new JWTDecodeException("签名不正确");
    }
    //取出payload
    String payload = split[1];
    //获取长度
    int length = payload.length() / 2;
    //指定截取点
    int index = payload.length() % 2 != 0 ? length + 1 : length;
    //混淆处理后的token
    return split[0] + "." + reversePayload(payload, index) + "." + split[2];
  }

  /**
   * 对一个混淆后的base编码进行解析
   * Authorization: Bearer <token>
   * @param token 混淆后的token
   */
  private static String deConfoundPayload(String token) throws Exception {
    if (StringUtils.isEmpty(token)) {
      throw new JWTDecodeException("you have no permission with token,please login!");
    }
    //分割token
    String[] split = token.split("\\.");
    //如果token不符合规范
    if (split.length != DEFAULT_TOKEN_SIZE) {
      throw new JWTDecodeException("you token is valid");
    }
    //取出payload
    String payload = split[1];
    //返回解析后的token
    return split[0] + "." + reversePayload(payload, payload.length() / 2) + "." + split[2];
  }

  /**
   * 将md5编码位移
   *
   * @param payload payload编码
   * @param index   位移处
   */
  private static String reversePayload(String payload, Integer index) {
    return payload.substring(index) + payload.substring(0, index);
  }
}

